'use strict';

var utils = require('./../utils');
var transformData = require('./transformData');
var isCancel = require('../cancel/isCancel');
var defaults = require('../defaults');

/**
 * Throws a `Cancel` if cancellation has been requested.
 */
// 检验是否需要取消请求
function throwIfCancellationRequested(config) {
    if (config.cancelToken) {
        config.cancelToken.throwIfRequested();
    }
}

/**
 * Dispatch a request to the server using the configured adapter.
 *
 * @param {object} config The config that is to be used for the request
 * @returns {Promise} The Promise to be fulfilled
 */
module.exports = function dispatchRequest(config) {
    // 检验是否需要取消请求
    throwIfCancellationRequested(config);

    // Ensure headers exist
    config.headers = config.headers || {};

    // Transform request data
    // 传入数据和请求头，并用transfromData进行修改
    // `transformRequest` 允许在向服务器发送前，修改请求数据
    // 它只能用与 'PUT', 'POST' 和 'PATCH' 这几个请求方法
    // 数组中最后一个函数必须返回一个字符串， 一个Buffer实例，ArrayBuffer，FormData，或 Stream
    // 你可以修改请求头。
    //   transformRequest: [function (data, headers) {
    //     // 对发送的 data 进行任意转换处理

    //     return data;
    //   }],
    // 这里的data是在发送请求前最终处理完成后返回的data
    // 调用transfrom处理请求前的参数
    config.data = transformData.call(
        config,
        config.data,
        config.headers,
        config.transformRequest //这一项作为回调函数
    );

    // Flatten headers
    // 处理优先级，用后进来的对象去修改和补充先进来的对象的属性参数
    // 抽出请求头的common和当前请求的methods合并到首层结构
    // 合并修改数据后的headers
    config.headers = utils.merge(
        config.headers.common || {},
        config.headers[config.method] || {},
        config.headers
    );
    // 清除配置头中的无用参数
    utils.forEach(
        ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
        function cleanHeaderConfig(method) {
            delete config.headers[method];
        }
    );
    // 处理，确认适配器
    // 执行adapter(config)返回Promise然后执行对应操作

    // 成功

    // 检测到如果请求已经取消则抛出错误
    // 否则处理返回数据格式
    // 失败

    //  // `adapter` 允许自定义处理请求，这使测试更加容易。
    //   // 返回一个 promise 并提供一个有效的响应 （参见 lib/adapters/README.md）。
    //   adapter: function (config) {
    //     /* ... */
    //   },
    var adapter = config.adapter || defaults.adapter;
    // 如果!isCancel(reason)成立,检测到如果请求已经取消则抛出错误
    // 否则直接返回数据
    // 注意,在这里的adapter在web环境默认走的是xhr.js中封装的AJAX请求
    return adapter(config).then(function onAdapterResolution(response) {
        // 适配器的成功回调
        throwIfCancellationRequested(config);
        // 处理并返回信息
        // Transform response data
        response.data = transformData.call(
            config,
            response.data,
            response.headers,
            // 对响应的数据进行统一处理
            config.transformResponse
        );

        return response;
    }, function onAdapterRejection(reason) {
        // 适配器的失败回调
        // 如果没有取消请求，继续对数据包数据进行处理
        if (!isCancel(reason)) {
            throwIfCancellationRequested(config);

            // Transform response data
            if (reason && reason.response) {
                // 请求失败也会对响应的data和响应头进行处理
                reason.response.data = transformData.call(
                    config,
                    reason.response.data,
                    reason.response.headers,
                    config.transformResponse
                );
            }
        }

        return Promise.reject(reason);
    });
};